`include "timescale.v"

module crc32 (
	input 		   reset, clk, enable, init,
	input  [7:0]   Data,
	output reg [31:0] Crc,
	output 		   CrcErr );

wire 	  [31:0]  CrcNext;

//when enable is 0, the CRC regs only shift left 8'bits each clk
assign CrcNext[0] = enable & (Data[7] ^ Data[1] ^ Crc[30] ^ Crc[24]);
assign CrcNext[1] = enable & (Data[7] ^ Data[6] ^ Data[1] ^ Data[0] ^ Crc[31] ^ Crc[30] ^ Crc[25] ^ Crc[24]);
assign CrcNext[2] = enable & (Data[7] ^ Data[6] ^ Data[5] ^ Data[1] ^ Data[0] ^ Crc[31] ^ Crc[30] ^ Crc[26] ^ Crc[25] ^ Crc[24]);
assign CrcNext[3] = enable & (Data[6] ^ Data[5] ^ Data[4] ^ Data[0] ^ Crc[31] ^ Crc[27] ^ Crc[26] ^ Crc[25]);
assign CrcNext[4] = enable & (Data[7] ^ Data[5] ^ Data[4] ^ Data[3] ^ Data[1] ^ Crc[30] ^ Crc[28] ^ Crc[27] ^ Crc[26] ^ Crc[24]);
assign CrcNext[5] = enable & (Data[7] ^ Data[6] ^ Data[4] ^ Data[3] ^ Data[2] ^ Data[1] ^ Data[0] ^ Crc[31] ^ Crc[30] ^ Crc[29] ^ Crc[28] ^ Crc[27] ^ Crc[25] ^ Crc[24]);
assign CrcNext[6] = enable & (Data[6] ^ Data[5] ^ Data[3] ^ Data[2] ^ Data[1] ^ Data[0] ^ Crc[31] ^ Crc[30] ^ Crc[29] ^ Crc[28] ^ Crc[26] ^ Crc[25]);
assign CrcNext[7] = enable & (Data[7] ^ Data[5] ^ Data[4] ^ Data[2] ^ Data[0] ^ Crc[31] ^ Crc[29] ^ Crc[27] ^ Crc[26] ^ Crc[24]);
assign CrcNext[8] = (enable & (Data[7] ^ Data[6] ^ Data[4] ^ Data[3] ^ Crc[28] ^ Crc[27] ^ Crc[25] ^ Crc[24])) ^ Crc[0];
assign CrcNext[9] = (enable & (Data[6] ^ Data[5] ^ Data[3] ^ Data[2] ^ Crc[29] ^ Crc[28] ^ Crc[26] ^ Crc[25])) ^ Crc[1];
assign CrcNext[10] = (enable & (Data[7] ^ Data[5] ^ Data[4] ^ Data[2] ^ Crc[29] ^ Crc[27] ^ Crc[26] ^ Crc[24])) ^ Crc[2];
assign CrcNext[11] = (enable & (Data[7] ^ Data[6] ^ Data[4] ^ Data[3] ^ Crc[28] ^ Crc[27] ^ Crc[25] ^ Crc[24])) ^ Crc[3];
assign CrcNext[12] = (enable & (Data[7] ^ Data[6] ^ Data[5] ^ Data[3] ^ Data[2] ^ Data[1] ^ Crc[30] ^ Crc[29] ^ Crc[28] ^ Crc[26] ^ Crc[25] ^ Crc[24])) ^ Crc[4];
assign CrcNext[13] = (enable & (Data[6] ^ Data[5] ^ Data[4] ^ Data[2] ^ Data[1] ^ Data[0] ^ Crc[31] ^ Crc[30] ^ Crc[29] ^ Crc[27] ^ Crc[26] ^ Crc[25])) ^ Crc[5];
assign CrcNext[14] = (enable & (Data[5] ^ Data[4] ^ Data[3] ^ Data[1] ^ Data[0] ^ Crc[31] ^ Crc[30] ^ Crc[28] ^ Crc[27] ^ Crc[26])) ^ Crc[6];
assign CrcNext[15] = (enable & (Data[4] ^ Data[3] ^ Data[2] ^ Data[0] ^ Crc[31] ^ Crc[29] ^ Crc[28] ^ Crc[27])) ^ Crc[7];
assign CrcNext[16] = (enable & (Data[7] ^ Data[3] ^ Data[2] ^ Crc[29] ^ Crc[28] ^ Crc[24])) ^ Crc[8];
assign CrcNext[17] = (enable & (Data[6] ^ Data[2] ^ Data[1] ^ Crc[30] ^ Crc[29] ^ Crc[25])) ^ Crc[9];
assign CrcNext[18] = (enable & (Data[5] ^ Data[1] ^ Data[0] ^ Crc[31] ^ Crc[30] ^ Crc[26])) ^ Crc[10];
assign CrcNext[19] = (enable & (Data[4] ^ Data[0] ^ Crc[31] ^ Crc[27])) ^ Crc[11];
assign CrcNext[20] = (enable & (Data[3] ^ Crc[28])) ^ Crc[12];
assign CrcNext[21] = (enable & (Data[2] ^ Crc[29])) ^ Crc[13];
assign CrcNext[22] = (enable & (Data[7] ^ Crc[24])) ^ Crc[14];
assign CrcNext[23] = (enable & (Data[7] ^ Data[6] ^ Data[1] ^ Crc[30] ^ Crc[25] ^ Crc[24])) ^ Crc[15];
assign CrcNext[24] = (enable & (Data[6] ^ Data[5] ^ Data[0] ^ Crc[31] ^ Crc[26] ^ Crc[25])) ^ Crc[16];
assign CrcNext[25] = (enable & (Data[5] ^ Data[4] ^ Crc[27] ^ Crc[26])) ^ Crc[17];
assign CrcNext[26] = (enable & (Data[7] ^ Data[4] ^ Data[3] ^ Data[1] ^ Crc[30] ^ Crc[28] ^ Crc[27] ^ Crc[24])) ^ Crc[18];
assign CrcNext[27] = (enable & (Data[6] ^ Data[3] ^ Data[2] ^ Data[0] ^ Crc[31] ^ Crc[29] ^ Crc[28] ^ Crc[25])) ^ Crc[19];
assign CrcNext[28] = (enable & (Data[5] ^ Data[2] ^ Data[1] ^ Crc[30] ^ Crc[29] ^ Crc[26])) ^ Crc[20];
assign CrcNext[29] = (enable & (Data[4] ^ Data[1] ^ Data[0] ^ Crc[31] ^ Crc[30] ^ Crc[27])) ^ Crc[21];
assign CrcNext[30] = (enable & (Data[3] ^ Data[0] ^ Crc[31] ^ Crc[28])) ^ Crc[22];
assign CrcNext[31] = (enable & (Data[2] ^ Crc[29])) ^ Crc[23];

always @ (posedge clk or posedge reset)
begin
  if (reset)
    Crc <=  32'hffffffff;
  else
  if(init)
    Crc <=  32'hffffffff;
  else
    Crc <=  CrcNext;
end

assign CrcErr = Crc[31:0] != 32'hc704dd7b;  // CRC not equal to magic number

// //for debug
// always @ (posedge clk)
// begin
//   if(enable)
// 	$display("%t: Data = %x, Crc = %x", $time, Data, Crc);	
// end

endmodule
